package com.jsb.laundry.common.utils.id;

import com.jsb.laundry.common.constant.CommonConstants;
import com.jsb.laundry.common.utils.redis.RedisUtil;
import com.jsb.laundry.common.utils.thread.ThreadUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.LongAdder;

/**
 * 根据当前时间生成订单编号
 *
 * @author zmy
 * @create 2022-11-13 11:17
 */
@Component
@DependsOn("redisUtil")
//在 "redisUtil" bean 加载和初始化后才能加载和初始化 OrderIDUtil 类。这样可以确保在加载 OrderIDUtil 类时，RedisUtil 已经被加载并注册到 IOC 容器中了
public class IDUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(IDUtil.class);

    private IDUtil() {
    }

    private static RedisUtil redisUtil;

    @Resource
    public void setRedisUtil(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }

    // 重置
    private static final LongAdder LONG_RESET = new LongAdder();

    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyMMddHHmmss");
//    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmssSSS");

    private static String LAST_TIME_STAMP = "";

    // 计数
    private static final AtomicLong COUNTER = new AtomicLong(0);
    private static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyMMdd");//yyMMdd
    private static final AtomicReference<String> STORE = new AtomicReference<>(DATE_TIME_FORMAT.format(LocalDateTime.now()));

    /**
     * 用于：支付ID
     * 格式为 23051700001
     *
     * @return
     */
    public static String getPayId() {
        String currentTimestamp = DATE_TIME_FORMAT.format(LocalDateTime.now());
        // 如果时间标识更改(每天重置)，重置计数器
        if (!STORE.get().equals(currentTimestamp)) {
            STORE.getAndSet(currentTimestamp);
            redisUtil.setCacheObject(CommonConstants.CURRENT_DAY_PAY_NUM, "0"); //每天第一笔支付 会重置 当前天支付id数量=0
        }
        Long currentDayPayIdNum = getCurrentDayPayIdNumber();
        long uniqueId = currentDayPayIdNum % 1000000;
        String number = String.format("%s%06d", currentTimestamp, uniqueId);
        LOGGER.info("生成支付单号==>{}", number);
        return number;
    }

    /**
     * redis中获取当天 已经拉起支付 用掉的 id数量[防止重启项目支付id重复]
     *
     * @return 获取当天支付单号数量(获取payId就 + 1)
     */
    private static Long getCurrentDayPayIdNumber() {
        Long count;
        String currentDayPayNum = redisUtil.getCacheObject(CommonConstants.CURRENT_DAY_PAY_NUM);
        if (currentDayPayNum == null) { //支付数量键不存在，就初始化
            redisUtil.setCacheObject(CommonConstants.CURRENT_DAY_PAY_NUM, "0");
            count = 1L;
        } else { //当天支付数量
            redisUtil.setCacheObject(CommonConstants.CURRENT_DAY_PAY_NUM, String.valueOf(Long.parseLong(currentDayPayNum) + 1));
            count = Long.parseLong(currentDayPayNum) + 1;
        }
        LOGGER.info("今天 已拉起支付次数==>{}", count);
        return count;
    }

    /**
     * 用于：订单ID
     *
     * @return
     */
    public static String getOrderId() {
        String currentTimestamp = SIMPLE_DATE_FORMAT.format(System.currentTimeMillis());
        // 如果时间戳更改，重置计数器
        if (!currentTimestamp.equals(LAST_TIME_STAMP)) {
            LAST_TIME_STAMP = currentTimestamp;
            LONG_RESET.reset();
        }
        LONG_RESET.increment();
        String number = String.format("%s%06d", currentTimestamp, LONG_RESET.longValue());
        LOGGER.info("生成订单单号==>{}",number);
        return number;
    }

    public static void main(String[] args) {
        ThreadUtil.runTasks(
                () -> {
                    // Task 1
                    for (int i = 0; i < 100; i++) {
                        Thread.currentThread().setName("Task 1【" + i + "】" + System.currentTimeMillis());
                        IDUtil.getOrderId();
                    }
                }
                ,
                () -> {
                    // Task 2
                    for (int i = 0; i < 100; i++) {
                        Thread.currentThread().setName("Task 2【" + i + "】" + System.currentTimeMillis());
                        IDUtil.getOrderId();
                    }
                },
                () -> {
                    // Task 3
                    for (int i = 0; i < 100; i++) {
                        Thread.currentThread().setName("Task 3【" + i + "】" + System.currentTimeMillis());
                        IDUtil.getOrderId();
                    }
                }
        );
    }
}
